﻿using System.Collections.Generic;
using DreamStore.WebShop.Models;
using DreamStore.WebShop.Settings;
using System;
using System.Linq;
using System.Web;
using System.Collections.Specialized;
using System.Net;
using System.IO;
using Orchard;
using Orchard.ContentManagement;

namespace DreamStore.WebShop.Services
{
    public class PayPalService : IPayPalService
    {
        private readonly IOrchardServices _orchardServices;

        public PayPalService(IOrchardServices orchardServices)
        {
            _orchardServices = orchardServices;
        }

        public PayPalRedirect ExpressCheckout(IEnumerable<OrderLine> orders)
        {
            var payPalSettings = _orchardServices.WorkContext.CurrentSite.As<PayPalApiSettingsPart>();

            var values = new NameValueCollection();

            values["METHOD"] = "SetExpressCheckout";
            values["RETURNURL"] = BuildReturnUrl(PayPalApiSettings.ReturnRouteName);
            values["CANCELURL"] = BuildReturnUrl(PayPalApiSettings.CancelRouteName);            
            values["PAYMENTACTION"] = "Sale";
            values["CURRENCYCODE"] = "DKK";
            values["BUTTONSOURCE"] = "PP-ECWizard";
            values["USER"] = payPalSettings.Username;
            values["PWD"] = payPalSettings.Password;
            values["SIGNATURE"] = payPalSettings.Signature;
            values["SUBJECT"] = "";
            values["VERSION"] = "72.0";

            decimal total = 0;            
            int num = 0;
            foreach (var orderLine in orders)
            {
                total += orderLine.TotalPrice;
                values["L_QTY" + num] = orderLine.Quantity.ToString("f").Replace(",", ".");
                values["L_NAME" + num] = orderLine.ProductName;
                values["L_AMT" + num] = orderLine.UnitPrice.ToString("f").Replace(",", ".");
                num++;
            }
            values["AMT"] = total.ToString("f").Replace(",", ".");
            values["ITEMAMT"] = total.ToString("f").Replace(",", ".");

            values = Submit(values);

            string ack = values["ACK"].ToLower();

            // debug ack here to check  - should return a success with the f trick above
            if (ack == "success" || ack == "successwithwarning")
            {
                return new PayPalRedirect
                {
                    Token = values["TOKEN"],
                    Url = String.Format("https://{0}/cgi-bin/webscr?cmd=_express-checkout&token={1}",
                       payPalSettings.CgiDomain, values["TOKEN"])
                };
            }
            else
            {
                // will result in an ysod with the relevant error msg returned from PayPal, ie. 'currency not supported' or similar
                throw new Exception(values["L_LONGMESSAGE0"]);
            }
        }

        private NameValueCollection Submit(NameValueCollection values)
        {
            var payPalSettings = _orchardServices.WorkContext.CurrentSite.As<PayPalApiSettingsPart>();

            string data = String.Join("&", values.Cast<string>()
              .Select(key => String.Format("{0}={1}", key, HttpUtility.UrlEncode(values[key]))));

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
               String.Format("https://{0}/nvp", payPalSettings.ApiDomain));

            request.Method = "POST";
            request.ContentLength = data.Length;

            using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
            {
                writer.Write(data);
            }

            using (StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream()))
            {
                return HttpUtility.ParseQueryString(reader.ReadToEnd());
            }
        }

        private string BuildReturnUrl(string routeName)
        {
            var url = _orchardServices.WorkContext.HttpContext.Request.Url;
            var applicationPath = _orchardServices.WorkContext.HttpContext.Request.ApplicationPath;
            return string.Format("http://{0}:{1}{2}/{3}", url.Host, url.Port,applicationPath, routeName);
            
        }
    }
}